#include "xunit_test.h"
#include "xdata_structure.h"
#include <fstream>


namespace xge{
namespace xge_internal{
  // internal test cast helper object
namespace {
  struct TestCaseContext : public Allocator {
    size_t loop ;
    UnitTest::UnitTestFinishCallBack call_back;
    UTBase* unit_test;
    TestCaseContext( UTBase* ut , size_t lp , UnitTest::UnitTestFinishCallBack cb ) : unit_test(ut),loop(lp),call_back(cb){}
  };
  typedef xge::map< String , TestCaseContext >::Map TestCaseMap ;
  typedef xge::map< String , TestCaseMap* >::Map TestFamilyMap;
  class TestFamilyMapAccessor {
  public:
    static TestFamilyMapAccessor& GetInstance() {
      static TestFamilyMapAccessor kInstance;
      return kInstance ;
    }
    void ClearUnitTest() {
      TestFamilyMap::iterator ib = kMap->begin() , ie = kMap->end();
      while( ib != ie ) {
        delete ((*ib).second) ;
        ++ib;
      }
      kMap->clear();
    }
    TestFamilyMap& Map() {
      return *kMap;
    }
  private:
    TestFamilyMapAccessor() {
      kMap = new TestFamilyMap();
    }
    ~TestFamilyMapAccessor() {
      ClearUnitTest();
      delete kMap;
    }
    TestFamilyMap * kMap;
  };
}// namespace

#define FAMILY_MAP TestFamilyMapAccessor::GetInstance().Map()

  static TestCaseMap* FindTestFamily ( const String& test_family , bool insert ) {
    typedef std::pair< typename TestFamilyMap::iterator , bool > ResultType;
    ResultType ret = FAMILY_MAP.insert( std::make_pair(test_family,(TestCaseMap*)NULL) );
    if( ret.second == false ) {
      return (*(ret.first)).second;
    } else {
      if( !insert ) {
        return NULL;
      }
      // insert one
      TestCaseMap* ptr = new TestCaseMap();
      (*(ret.first)).second = ptr;
      return ptr;
    }
  }

  static TestCaseContext* FindUnitTest( const String& test_family , const String& test_case_name ) {
    TestCaseMap* case_map = FindTestFamily( test_family , false );
    if( case_map == NULL ) {
      return NULL;
    }
    TestCaseMap::iterator ret = case_map->find(test_case_name);
    if( ret == case_map->end() ) {
      return NULL;
    } else {
      return &((*ret).second);
    }
  }

  static bool RemoveUnitTest( const String& test_family , const String& test_case_name ) {
    TestCaseMap* case_map = FindTestFamily( test_family , false );
    if( case_map == NULL ) {
      return false;
    }
    TestCaseMap::iterator ret = case_map->find(test_case_name);
    if( ret == case_map->end() ) {
      return false;
    } else {
      case_map->erase(ret);
      return true;
    }

  }


  bool UnitTest::RegisterUnitTestCase( UTBase* base ,const String& test_family , 
    const String& test_case_name , 
    size_t loop /* = 1  */, 
    UnitTestFinishCallBack call_back /* = NULL */ ) {
    TestCaseContext target(base,loop,call_back);
    TestCaseMap* case_map = FindTestFamily(test_family,true);
    typedef std::pair< typename TestCaseMap::iterator , bool > ResultType;
    ResultType ret = case_map->insert( std::make_pair(test_case_name,target) );
    if( ret.second == false ) {
      // error
      return false;
    } else {
      // register ok
      return true;
    }
  }


  static void RunSingleTestCase( const TestCaseContext& ctx , const String& family_name , const String& test_case_name ) {
    ctx.unit_test->SetUp();
    for( size_t i = 0 ; i < ctx.loop ; ++i ) {
      ctx.unit_test->UnitTest();
    }
    ctx.unit_test->TearDown();
    if( ctx.call_back ) {
      ctx.call_back(ctx.unit_test);
    }
  }

  void UnitTest::RunAllUnitTest() {
#ifdef XGE_USE_WIDE_CHAR
    std::wfstream 
#else
    std::fstream
#endif
      file("XUnitTestLogFile.log",std::ios::in|std::ios::out|std::ios::trunc);
    file<<"------------------------X unittest record file------------------------\n\n";
    TestFamilyMap::iterator ib = FAMILY_MAP.begin();
    TestFamilyMap::iterator ie = FAMILY_MAP.end();
    while( ib != ie ) {
      TestCaseMap::iterator case_ib = (*ib).second->begin();
      TestCaseMap::iterator case_ie = (*ib).second->end();

      while( case_ib != case_ie ) {
        TestCaseContext & ctx = (*case_ib).second;
        // Just a simple record stub for this test case
        file<<"----------------------------------------\n";
        file<<"A test cast has run.\n"<<"Family name: "
          <<((*ib).first).c_str()
          <<"\nCast Name: "
          <<(*case_ib).first.c_str()
          <<"\n----------------------------------------"<<std::endl;
        // Run the single test case
        RunSingleTestCase(ctx,(*ib).first,(*case_ib).first);
        ++case_ib;
      }
      ++ib;
    }
    TestFamilyMapAccessor::GetInstance().ClearUnitTest();
  }

  bool UnitTest::RunFamilyTest( const String& test_family ) {
    TestCaseMap* case_map = FindTestFamily(test_family,false);
    if( case_map == NULL ) {
      return false;
    }
    TestCaseMap::iterator ib = case_map->begin() , ie = case_map->end();
    while( ib != ie ) {
      TestCaseContext & ctx = (*ib).second;
      RunSingleTestCase(ctx,test_family,ib->first);
      ++ib;
    }
    case_map->clear();
    return true;
  }

  bool UnitTest::RunSingleTest( const String& test_family , const String& test_case_name ) {
    TestCaseContext* pCtx = FindUnitTest(test_family,test_case_name);
    if( pCtx == NULL ) {
      return false;
    }
    RunSingleTestCase(*pCtx,test_family,test_case_name);
    return RemoveUnitTest(test_family,test_case_name);
  }

  bool UnitTest::IsRegistered(const String& test_family ,const String& test_case_name) {
    return FindUnitTest(test_family,test_case_name) != NULL;
  }
#undef FAMILY_MAP

}// namespace xge_internal
}// namespace xge